#include<iostream>
// class Empty{};

// class empty{
//     public:
//     empty()
//     {}
//     ~empty()
//     {}
//     empty(const empty& rhs)
//     {}
//     empty& operator=(const empty& rhs)
//     {}
// };  

// template<typename T>
// class NameObject
// {
//     private:
//         std::string _namevalue;
//         T _objectvalue;
//     public:
//         NameObject(const char* namevalue,const T& objectvalue);
//         NameObject(const std::string& namevalue,const T& objectvalue);
// };

// template<typename T>
// class NameObject
// {
//     private:
//         std::string& _namevalue;
//         T _objectvalue;
//     public:
//         NameObject(const std::string& namevalue,const T& objectvalue);
// };
// //考虑定义operator=会发生什么?
// std::string newDog("persephone");
// std::string oldDog("satch");
// NameObject<int> p(newDog,2);
// NameObject<int> s(oldDog,32);
// p = s;//p的成员变量会发生什么?
// //内含reference成员 和 const 成员的class 内 无法使用默认copy assign


// class HomeForSale
// {
//     public:
//     private:
//     HomeForSale(const HomeForSale&);
//     HomeForSale& operatro=(const HomeForSale&);
// };
// class Uncopyalbe
// {
//     public:
//     Uncopyalbe()
//     {}
//     ~Uncopyalbe()
//     {}
//     private:
//     Uncopyalbe(const Uncopyalbe&);
//     Uncopyalbe& operator=(const Uncopyalbe&);
// };

// class HomeForSale:private Uncopyalbe//class 不再声明 copy构造函数 和 copyassign 操作符
// {
//     public:
//     private:
// }
// //原理解释:任何人只要(包括member 和 friend 函数) -->尝试调用拷贝HomeForSale类对象,编译器会试着生成一个拷贝构造和赋值,
// //这些函数的"编译器生成版"会尝试调用base class 的对应兄弟,这些调用会被拒绝,因为其base class 的拷贝函数是 private;
// int main()
// {

//     return 0;
// }

//07为多态基类声明virtual析构函数
class TimeKeeper{
    public:
        TimeKeeper()
        {}
        // ~timer_create()
        // {

        // }
        virtual ~TimerKeeper()
        {}
};
class AtomClock::public TimeKeeper{};
class WaterClock::public TimeKeeper{};
class WristWatch::public TimeKeeper{};

TimeKeeper* GetTimer()
{

}

//2. lass不含virtual函数,通常表示它并不意图被用作base class.当class不意图做base class时, 令析构函数为虚函数,是一个坏主意,
//添加虚函数,;每个对象会携带虚表指针,会增加每个对象的体积.
//错误用法:string 中没有虚析构函数,会有资源泄露
class SpecialString:public std::string {

};
SpecialString* pss = new SpecialString("Impending Doom");
std::string* ps;
ps = pss;
delete ps;//此时会有未定义行为,*ps 的SpecialString资源会泄漏
// int main()
// {

//     // TimeKeeper* tk =  GetTimer();
//     // delete tk; //此时会资源泄漏,基类的析构函数没有virtual析构函数时,当一个指向子类的指针,经由基类被删除时会引起资源泄露
//     //为什么? 当delete tk,时tk指向子类对象的成分(声明与子类对象中的成员变量)没有被删除,子类的析构函数也没有被调用.
//     //当基类析构函数为虚函数时, delete tk时, 子类和基类的析构函数构成了多态,即子类的析构重写了基类的析构函数.当调用子类析构函数时后,会自动调用基类的析构函数.
// 多态性质的base class 应该声明为一个virtual析构函数,如果class 带有任何virtual虚函数应该拥有一个virtual函数
// class 的设计目的如果不是为了base class使用, 或不是为了具备多态性,就不该声明virtual析构函数.
//     return 0;
// }


//条款:08别让异常逃离析构函数
// class Widget{
//     public:
//         Widget()
//         {}
//         ~Widget()
//         {}
//     private:
// };

// void DoSomething()
// {
//     std::vector<Widget> v;
// }
// //此时当v被销毁时,应当销毁所有的Widget,当第一个Widget析构函数异常时,导致后续所有的Widget都不会被销毁,从而内存泄漏

// class DBConnection
// {
//     public:
//     static DBConnection create();
//     void close();
//     private:

// };

// class DBCon{
//     public:
//         ~DBCon()    //确保数据库总是被关闭
//         {
//             db.close();
//         }
//     private:
//         DBConnection db;
// };


// {
//     DBCon con(DBConnection::create());//当函数块结束时,自动调用析构函数关闭连接
// }
// //当close函数出现异常时,会传播异常,导致问题
// //方法一:处理异常
// DBCon::~DBCon()
// {
//     try {db.close()}
//     catch(...)//当db.close()发生异常时,调用abort()函数
//     {
//         std::abort();
//     }
// }
// //方法二:吞下异常
// DBCon::~DBCon()
// {
//     try(db.close();)
//     catch(...)
//     {
//         //制作运转记录,记下对close的调用失败
//     }
// }


// //方法三:使用异构函数以外的函数提醒用户
// class DBcon{
//     public:
//         void close()//提供给用户的关闭连接的函数
//         {
//             db.close();
//             closed = true;
//         }
//         ~DBCon()
//         {
//             if(!closed)
//             {
//                 //关闭连接(如果用户不那么做的话)
//                 try(db.close();)
//             }
//             catch(...)
//             {
//                 //制作运转记录,记下对close的调用失败
//             }

//         }
//     private:
//         DBConnection db;
//         bool closed;
// };

//总结:1. 析构函数绝不要吐出异常,如果一个被析构函数调用的函数可能抛出异常,则析构函数应该捕捉任何异常,然后吞下他们不传播,或结束程序
//2. 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供普通函数执行该操作.



// // 条款09:绝不在构造和析构函数中调用virtual函数
// class Transaction{
//     public:
//         Transaction()
//         {}
//         virtual void logTransaction() const  = 0; //做出一份因类型不不同而不同的日志函数
//     private:
// };
// Transaction::Transaction()
// {
//     logTransaction();        //调用virtual函数
// }

// class ButTransaction :public Transaction
// {
//     public:
//         virtual void logTransaction() const;
//     private:
// };
// class SellTransaction : public Transaction
// {
//     public:
//         virtual void logTransaction();
//     private:
// }

// class Transaction
// {
//     public:
//         Transaction()
//         {
//             init();
//         }
//         virtual void logTransaction() const = 0;
//     private:
//     void init()
//     {
//         logTransaction();
//     }
// };

// //避免次问题的做法是:确定构造函数和析构函数(在对象被创建和被销毁期间)都没有调用virtual函数,而他们调用的所有函数都服从统一约束.


// //其他方案解决问题:
// //一种做法是在class Transaction内将logTransaction 函数改为non-virtual函数,然后要求derived class 构造函数传递必要信息给Transaction 构造函数,而后那个构造函数便可以安全的调用功能non-virtual logTransaction
// class Transaction
// {
//     public:
//     explicit Transaction(const std::string& logInfo);
//     void logTransaction(const std::string& logTnfo);
//     private:
// };

// Transaction::logTransaction(const std::string logInfo)
// {
//     logTransaction();//此时是non-virtual函数调用
// }
// class BuyTransaction:public Transaction
// {
//     public:
//         ButTransaction(int parameters)
//         :Transaction(createLogString(int parameters))
//         {}
//     private:
//         //令函数为static,就不可能意外指向"初期未成熟之BuyTransaction对象内尚未初始化的成员变量"
//         //为什么?static函数属于类,而不属于某个具体对象的.它不依赖对象的状态,因此不会访问对象的成员变量,
//         // 所以,将createLogString声明为static可以确保在构造函数调用它时不会访问到尚未初始化的成员变量.

//         static std::string createLogString(int parameters);
// };


// //结论:在构造和析构函数间不要调用virtual函数,因为这类调用从不会下降到子类(比起当前执行的构造函数和析构函数那层)
// int main()
// {
//     ButTransaction bt;   //此时会调用ButTransaction类的构造函数被调用,但是会先调用基类的构造函数,又因为在基类的构造期间会调用virtual函数
//     //此时调用的虚函数时base class中的,base class 类的构造函数期间绝不会下降到子类的阶层,在base class 类的构造函数期间,virtua函数不是virtual函数
//     //如果在基类的构造函数期间下降到子类阶层,子类的函数几乎必然会调用local成员变量.而这些成员变量未初始初始化,而引发不明确行为
//     //更根本的原因是:在drivaed class 对象的base class构造期间对象的类型是base class,而不是derived class,对象在derived class构造函数执行之前不会成为一个derived 类对象
//     // 析构函数是同样的道理,一旦derived class析构函数开始执行,对象内的derived class成员变量呈现未定义值
    
// }



// //条款10: 令operator=返回一个reference to *this
// class Widget
// {
//     public:
//         Widget()
//         {
//         }
//         Widget& operator=(const Widget& rhs)
//         {
//             return *this;
//         }
//         Widget& operator+=(const Widget& rhs)
//         {
//             return *this;
//         }
//         Widget& operator=(int rhs)
//         {
//             return *this;
//         }
// };
//结论:令赋值操作返回一个reference to *this;


// 条款11:operator=中处理"自我赋值"
class Widget{
    public:
        Widget()
        {}

    private:
};
int main()
{
    w = w;//自我赋值
    a[i] = a[j];//潜在的自我赋值
    *px = *pj;//潜在的自我赋值
    return 0;
}

class Base{};
class Derived: public Base{};
void doSomething (const Base& rb,Derived* pd); //此时rb和 *pd有可能是同一对象



// 实验二
class Bitmap{

};
class Wiget
{
    private:
    Bitmap* pb;
}

//不安全的operator实现此时,*this和rhs有可能是同一个对象
Widget& Widget::operator=(const Widget& rhs)
{
    delete pb;
    pb = new Bitmap(*rhs.pb);
    return *this;
}

// 解决方法:证同测试
Widget& Widget::operator=(const Wiget& rhs)
{
    if(*this == rhs) return *this;
    delete pb;
    pb = new Bitmap(*rhs.pb);
    return *this;
}

//保证异常安全性
Widget& Widget::operator=(const Widget& rhs)
{
    Bitmap* temp = pb;
    pb = new Bitmap(*rhs.pb);
    delete pOrig;
    return *this;
}



//保证异常安全和自我赋值安全: copy and swap 技术
class Widget
{
    void swap(Widget& rhs);
}
Widget& Widget::operator=(const Widget& rhs)
{
    Widget temp(rhs);//为rhs数据制作一份复件
    swap(temp);      //将*this数据和上述复件的数据交换
    return *this;
}

Widget& Widget::operator=(const Widget rhs)
{
    swap(rhs);
    return *this;
}


//结论:确保当前对象自我赋值时operator= 有良好的行为,其中技术包括"来源对象"和"目标对象"的地址, 精心周到的语句顺序,以及copy and swap技术
//确定任何函数如果操作一个以上的对象,而其中多个对象是同一对象时,其行为仍然正确.


//条款12:复制对象时不要忘记其每一个成分
// 实验一
void logCall(const std::string& funcName);  //制造一个log entry
class Customer
{
    public:
        Customer(const Customer& rhs);
        Customer& operator=(const Customer& rhs); 
    private:
    std::string _name;
};

Customer::Customer(const Customer& rhs)
:_name(rhs._name)
{
    logCall("Customer copy constructor");
}
Customer& Customer::operator=(const Customer& rhs)
{
    logCall("Customer copy constructor");
    _name = rhs._name;
    return *this;
}


//此时情况发送改变
class Date{};
class Customer{
    public:
    private:
        std::string name;
        Date LastTransaction;
};


class priorityCustomer:public Customer
{
    public:
        priorityCustomer(const priorityCustomer& rhs);
        priorityCustomer& operator=(const priorityCustomer& rhs);
    private:
        int priority;
};

//这两个copu函数没有指定参数给base class 类的构造函数,即它们的初始化列表中没有提到customer) 
// 因此priorityCustomer对象中的Customer成分会被不带实参的Customer构造函数初始化,
//default构造函数将针对name 和 lastTransaction执行缺省的初始化动作.
priorityCustomer::priorityCustomer(const priorityCustomer& rhs)
:priority(rhs.priority)
{
    logCall("priorityCustomer copy constructor");
}
priorityCustomer& operator=(const priorityCustomer& rhs)
{
    logCall("priorityCustomer copy assignment operator");
    priority = rhs.priority;
    return *this;
}


//禁忌任何时候只要你承担起"为derived class 撰写copying函数时"的重大责任,必须小心的复制其base class 成分,
// 那些成分往往是private,所以你无法直接访问它,应该让derived class 的copying 函数 调用相应的base class 函数
priorityCustomer::priorityCustomer(const priorityCustomer& rhs)
:Customer(rhs)                      //调用base class 的copy构造函数
,priority(rhs.priority)             
{
    logCall("priorityCustomer copy constructor");
}
priorityCustomer& priorityCustomer::operator=(cosnt priorityCustomer& rhs)
{
    logCall("priorityCustomer copy assignment operator");
    Customer::operator=(rhs);      //对base class 成分进行赋值动作
    priority = rhs.priority;
    return *this;
}

// 结论:1. Copying 函数应该确保复制"对象内的所有成员变量"及所有"base class 成分"
//2. 不要尝试一某个拷贝函数实现另一个拷贝函数,应该将共同机制放入第三个函数中,并由两个copying函数共同调用.

//条款13: 以对象管理资源
class investment{};
investment* CreatInvestment();
void function{
    investment* Pinv = CreatInvestment();
    delete Pinv;
}
//使用RAII
void f()
{
    std::auto_ptr<investment> Pinv(CreatInvestment());//以Pinv对象管理资源
}

//auto_ptr的特性资源的唯一拥有权
std::auto_ptr<investment> Pinvl(CreatInvestment());
std::auto_tpr<investment> Pinv2(Pinvl);//此时Pinv2指向对象,Pinv1为空
pInv1 = pInv2;//此时PInv2被设置为null,pInv1指向对象


void f()
{
    std::trl::shared_ptr<investment> pInv(CreatInvestment());
}
void f()
{
    std::trl::shared_ptr<investment> pInv(CreatInvestment());
    std::trl::shared_ptr<investment> pInv2(pInv);//此时指向同一个目标
    pInv = pInv2;//此时指向同一目标,同上
}



std::auto_ptr<std::string> aps(new std::string[10]);//错误
std::trl::shared_ptr<int> spi(new int[1024]);//错误
//两者都都是在其析构函数内做delete而不是delete[]动作


//使用boost库 
boost::scoped_array 和 boost::shared_array class
//总结:为防止资源泄露,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源
//两个常被使用的RAII class 分别是:trl::shared_ptr,auto_ptr,前者通常是最佳选择,因为copy的行为比较直接.

// 让结构容易被正确使用,不易被误用
class Date{
    public:
    Date(int month,int day, int year);
}
struct Day{
    explicit Day(int d)
    :val(d)
    {}
    int val;
};
struct Month{
    explicit Day(int m)
    :val(m)
    {}
    int val;
};
struct year{
    explicit Day(int y)
    :val(y)
    {}
    int val;
};


class Date{
    public:
    Date(const Month& m, const Day& d, const Year& y);
}

Date d(Month(3),Day(30),year(1995));
class Month{
    public:
        static Month Jan()
        {
            return Month(1);
        }
        static Month Feb()
        {
            return Month(2);
        }


    private:
    explicit Month(int m);
};

Date d(Month::Feb(),Day(30), year(1994));


// 假设class设计者期许"从 createInvestment"取得Investment* 指针的客户将该指针传给一个名为getRidofInvestment的函数,//企图使用错误的析构机制
//而不是直接在它身上动刀(使用delete)
//解决方法:返回一个"将getRidOfInvestment"绑定为删除器的trl::shared_ptr
// std::trl::shared_ptr<investment*> pinv(static_cast<investment*>(0),getridofvestment);//建立一个nullshared_Ptr,并以getridofvestment作为删除器

// std::trl::shared_ptr<investment> CreatInvestment()
// {
//     std::trl::shaed_ptr<investment> retVal(static_cast<investment*>(0),getridofvestment);
//     retVal = ..;//令retVal指向正确的对象
//     return retVal;
// }



// // trl::shared_ptr : 性质:自动使用它的"每个指针专属的删除器"消除"cross-DLL problem"
// std::trl::shared_ptr<investment> CreatInvestment()
// {
//     return std::trl::shared_ptr<investment>(new stock);
// }
//返回的trl::shared_ptr 可被传递给任何其他DLLS,当指向Stock的trl::shared_ptr会追踪记录"当stock的引用计数为0时,该调用那个DLL,delete

//总结:接口的一致性,与内置类型的行为兼容
//shared_ptr支持定制型删除器,可防范DLL问题,可被用来自动解除互斥锁等


//条款14:在资源管理类中小心 copying 行为
class Lock
{
    public:
    Lock(Mutex* mutex)
    :_mutex(mutex)
    {
        lock(_mutex);
    }
    ~Lock()
    {
        unlock(_mutex);
    }
    private:
    Mutex* _mutex;
};

#include<pthread.h>
#include<iostream>
#include<memory>
class Mutex
{
    public:
    private:
};
Mutex m;

Lock m12(&m);
Lock m12(m11); //此时会错误
class Lock: private Uncopyable
{
    public:
};

//解决方法: 禁止赋值
//2. 对底层资源祭出"引用计数法"

class Lock
{
    public: 
        explicit Lock(Mutex* pm)
        :mutexPtr(pm,unlock)
        {
            lock(mutexPtr.get());
        }
    private:
        std::shared_ptr<Mutex> mutexPtr;
};



